home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / nethack.lha / nethack-3.1 / src / dokick.c < prev    next >
C/C++ Source or Header  |  1993-01-22  |  32KB  |  1,224 lines

  1. /*    SCCS Id: @(#)dokick.c    3.1    92/10/06    */
  2. /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. #include    "hack.h"
  6. #include    "eshk.h"
  7.  
  8. #ifndef POLYSELF
  9. # define martial()    (pl_character[0] == 'S' || pl_character[0] == 'P')
  10. #else
  11. # define is_bigfoot(x)    ((x) == &mons[PM_SASQUATCH])
  12. # define martial()    (pl_character[0] == 'S' || pl_character[0] == 'P' \
  13.              || is_bigfoot(uasmon))
  14. #endif
  15.  
  16. static struct rm NEARDATA *maploc;
  17.  
  18. extern boolean notonhead;    /* for long worms */
  19.  
  20. static void FDECL(kickdmg, (struct monst *, BOOLEAN_P));
  21. static void FDECL(kick_monster, (XCHAR_P, XCHAR_P));
  22. static int FDECL(kick_object, (XCHAR_P, XCHAR_P));
  23. static char *NDECL(kickstr);
  24. static void FDECL(otransit_msg, (struct obj *, XCHAR_P, BOOLEAN_P, int));
  25. static const char *FDECL(gate_str, (XCHAR_P));
  26. static void FDECL(drop_to, (coord *, XCHAR_P));
  27.  
  28. static struct obj NEARDATA *kickobj;
  29.  
  30. #define IS_SHOP(x)    (rooms[x].rtype >= SHOPBASE)
  31.  
  32. static void
  33. kickdmg(mon, clumsy)
  34. register struct monst *mon;
  35. register boolean clumsy;
  36. {
  37.     register int mdx, mdy;
  38.     register int dmg = ( ACURRSTR + ACURR(A_DEX) + ACURR(A_CON) )/ 15;
  39.  
  40.     /* excessive wt affects dex, so it affects dmg */
  41.     if(clumsy) dmg = dmg/2;
  42.  
  43.     /* kicking a dragon or an elephant will not harm it */
  44.     if(thick_skinned(mon->data)) dmg = 0;
  45.  
  46.     /* a good kick exercises your dex */
  47.     exercise(A_DEX, TRUE);
  48.  
  49.     /* squeeze some guilt feelings... */
  50.     if(mon->mtame) {
  51. #ifdef SOUNDS
  52.         if (rn2(10)) yelp(mon);
  53.         else growl(mon); /* give them a moment's worry */
  54. #endif
  55.         mon->mtame--;
  56.         if(!mon->mtame) newsym(mon->mx, mon->my);
  57.         mon->mflee = mon->mtame ? 1 : 0;
  58. #ifdef HISX
  59.         mon->mfleetim = mon->mfleetim + (dmg ? rnd(dmg) : 1);
  60. #else
  61.         mon->mfleetim += (dmg ? rnd(dmg) : 1);
  62. #endif
  63.     }
  64.  
  65.     if (dmg)
  66.         mon->mhp -= (!martial() ? rnd(dmg) :
  67.             rnd(dmg)+rnd(ACURR(A_DEX)/2));
  68.     if(mon->mhp < 1) {
  69.         (void) passive(mon, TRUE, 0, TRUE);
  70.         killed(mon);
  71.         return;
  72.     }
  73.     if(martial() && !bigmonst(mon->data) && !rn2(3) && mon->mcanmove) {
  74.         /* see if the monster has a place to move into */
  75.         mdx = mon->mx + u.dx;
  76.         mdy = mon->my + u.dy;
  77.         if(goodpos(mdx, mdy, mon, mon->data)) {
  78.             pline("%s reels from the blow.", Monnam(mon));
  79.             remove_monster(mon->mx, mon->my);
  80.             place_monster(mon, mdx, mdy);
  81.             newsym(mon->mx, mon->my);
  82.             set_apparxy(mon);
  83.         }
  84.     }
  85.     (void) passive(mon, FALSE, 1, TRUE);
  86.  
  87. /*    it is unchivalrous to attack the defenseless or from behind */
  88.     if (pl_character[0] == 'K' &&
  89.         u.ualign.type == A_LAWFUL && u.ualign.record > -10 &&
  90.         (!mon->mcanmove || mon->msleep || mon->mflee))
  91.         adjalign(-1);
  92.  
  93. }
  94.  
  95. static void
  96. kick_monster(x, y)
  97. register xchar x, y;
  98. {
  99.     register boolean clumsy = FALSE;
  100.     register struct monst *mon = m_at(x, y);
  101.     register int i, j;
  102.  
  103.     bhitpos.x = x;
  104.     bhitpos.y = y;
  105.     if(special_case(mon)) return;
  106.     setmangry(mon);
  107. #ifdef POLYSELF
  108.     /* Kick attacks by kicking monsters are normal attacks, not special.
  109.      * If you have >1 kick attack, you get all of them.
  110.      */
  111.     if (attacktype(uasmon, AT_KICK)) {
  112.         schar tmp = find_roll_to_hit(mon);
  113.         for(i=0; i<NATTK; i++) {
  114.         if (uasmon->mattk[i].aatyp == AT_KICK && multi >= 0) {
  115.             /* check multi; maybe they had 2 kicks and the first */
  116.             /* was a kick against a floating eye */
  117.             if (tmp > rnd(20)) {
  118.             int sum;
  119.  
  120.             You("kick %s.", mon_nam(mon));
  121.             sum = damageum(mon, &(uasmon->mattk[i]));
  122.             if (sum == 2)
  123.                 (void)passive(mon, 1, 0, TRUE);
  124.             else (void)passive(mon, sum, 1, TRUE);
  125.             } else {
  126.             missum(mon, &(uasmon->mattk[i]));
  127.             (void)passive(mon, 0, 1, TRUE);
  128.             }
  129.         }
  130.         }
  131.         return;
  132.     }
  133. #endif
  134.  
  135.     /* no need to check POLYSELF since only ghosts, which you can't turn */
  136.     /* into, are noncorporeal */
  137.     if(noncorporeal(mon->data)) {
  138.         Your("kick passes through!");
  139.         return;
  140.     }
  141.  
  142.     if(Levitation && !rn2(3) && verysmall(mon->data) &&
  143.        !is_flyer(mon->data)) {
  144.         pline("Floating in the air, you miss wildly!");
  145.         exercise(A_DEX, FALSE);
  146.         (void) passive(mon, FALSE, 1, TRUE);
  147.         return;
  148.     }
  149.  
  150.     i = -inv_weight();
  151.     j = weight_cap();
  152.  
  153.     if(i < (j*3)/10) {
  154.         if(!rn2((i < j/10) ? 2 : (i < j/5) ? 3 : 4)) {
  155.             if(martial() && !rn2(2)) goto doit;
  156.             Your("clumsy kick does no damage.");
  157.             (void) passive(mon, FALSE, 1, TRUE);
  158.             return;
  159.         }
  160.         if(i < j/10) clumsy = TRUE;
  161.         else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE;
  162.     }
  163.  
  164.     if(Fumbling) clumsy = TRUE;
  165.  
  166.     else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25))
  167.         clumsy = TRUE;
  168. doit:
  169.     You("kick %s.", mon_nam(mon));
  170.     if(!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) &&
  171.        mon->mcansee && !mon->mtrapped && !thick_skinned(mon->data) &&
  172.        mon->data->mlet != S_EEL && haseyes(mon->data) && mon->mcanmove &&
  173.        !mon->mstun && !mon->mconf && !mon->msleep &&
  174.        mon->data->mmove >= 12) {
  175.         if(!nohands(mon->data) && !rn2(martial() ? 5 : 3)) {
  176.             pline("%s blocks your %skick.", Monnam(mon),
  177.                 clumsy ? "clumsy " : "");
  178.             (void) passive(mon, FALSE, 1, TRUE);
  179.             return;
  180.         } else {
  181.             mnexto(mon);
  182.             if(mon->mx != x || mon->my != y) {
  183.             pline("%s %s, %s evading your %skick.", Monnam(mon),
  184.                 (can_teleport(mon->data) ? "teleports" :
  185.                  is_floater(mon->data) ? "floats" :
  186.                  is_flyer(mon->data) ? "flutters" :
  187.                  nolimbs(mon->data) ? "slides" :
  188.                  "jumps"),
  189.                 clumsy ? "easily" : "nimbly",
  190.                 clumsy ? "clumsy " : "");
  191.             (void) passive(mon, FALSE, 1, TRUE);
  192.             return;
  193.             }
  194.         }
  195.     }
  196.     kickdmg(mon, clumsy);
  197. }
  198.  
  199. /*
  200.  *  Return TRUE if caught (the gold taken care of), FALSE otherwise.
  201.  *  The gold object is *not* attached to the fobj chain!
  202.  */
  203. boolean
  204. ghitm(mtmp, gold)
  205. register struct monst *mtmp;
  206. register struct obj *gold;
  207. {
  208.     if(!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest
  209. #ifdef ARMY
  210.         && !is_mercenary(mtmp->data)
  211. #endif
  212.         ) {
  213.         wakeup(mtmp);
  214.     } else if (!mtmp->mcanmove) {
  215.         /* too light to do real damage */
  216.         if (canseemon(mtmp))
  217.             pline("The gold hits %s.", mon_nam(mtmp));
  218.     } else {
  219.         mtmp->msleep = 0;
  220.         mtmp->meating = 0;
  221.         if(!rn2(4)) setmangry(mtmp); /* not always pleasing */
  222.  
  223.         /* greedy monsters catch gold */
  224.         if (cansee(mtmp->mx, mtmp->my))
  225.             pline("%s catches the gold.", Monnam(mtmp));
  226.         mtmp->mgold += gold->quan;
  227.         if (mtmp->isshk) {
  228.             long robbed = ESHK(mtmp)->robbed;
  229.  
  230.             if (robbed) {
  231.                 robbed -= gold->quan;
  232.                 if (robbed < 0) robbed = 0;
  233.                 pline("The amount %scovers %s recent losses.",
  234.                     !robbed ? "" : "partially ",
  235.                     mtmp->female ? "her" : "his");
  236.                 ESHK(mtmp)->robbed = robbed;
  237.                 if(!robbed)
  238.                     make_happy_shk(mtmp, FALSE);
  239.             } else {
  240.                 if(mtmp->mpeaceful) {
  241.                     ESHK(mtmp)->credit += gold->quan;
  242.                     You("have %ld zorkmid%s in credit.",
  243.                     ESHK(mtmp)->credit,
  244.                     plur(ESHK(mtmp)->credit));
  245.                 } else verbalize("Thanks, scum!");
  246.             }
  247.         }
  248.         else if(mtmp->ispriest) {
  249.             if(mtmp->mpeaceful)
  250.                 verbalize("Thank you for your contribution.");
  251.             else verbalize("Thanks, scum!");
  252.         }
  253.         else if(is_mercenary(mtmp->data)) {
  254.             if(rn2(3)) {
  255.             if(mtmp->data == &mons[PM_SOLDIER]) {
  256.                if(gold->quan > 100 + (u.ugold + (u.ulevel*rn2(5)))
  257.                         /ACURR(A_CHA))
  258.                 mtmp->mpeaceful = 1;
  259.                 }
  260.             if(mtmp->data == &mons[PM_SERGEANT]) {
  261.                if(gold->quan > 250 + (u.ugold + (u.ulevel*rn2(5)))
  262.                         /ACURR(A_CHA))
  263.                 mtmp->mpeaceful = 1;
  264.                 }
  265.             if(mtmp->data == &mons[PM_LIEUTENANT]) {
  266.                if(gold->quan > 500 + (u.ugold + (u.ulevel*rn2(5)))
  267.                         /ACURR(A_CHA))
  268.                 mtmp->mpeaceful = 1;
  269.                 }
  270.             if(mtmp->data == &mons[PM_CAPTAIN]) {
  271.                if(gold->quan > 750 + (u.ugold + (u.ulevel*rn2(5)))
  272.                         /ACURR(A_CHA))
  273.                 mtmp->mpeaceful = 1;
  274.                 }
  275.              }
  276.              if(mtmp->mpeaceful)
  277.                 verbalize("That should do.  Now beat it!");
  278.              else verbalize("That's not enough, coward!");
  279.              }
  280.  
  281.         dealloc_obj(gold);
  282.         return(1);
  283.     }
  284.     return(0);
  285. }
  286.  
  287. static int
  288. kick_object(x, y)
  289. xchar x, y;
  290. {
  291.     int range;
  292.     register struct monst *mon, *shkp;
  293.     register struct obj *otmp;
  294.     struct trap *trap;
  295.     boolean costly, insider, shipit;
  296.     boolean isgold;
  297.  
  298.     /* if a pile, the "top" object gets kicked */
  299.     kickobj = level.objects[x][y];
  300.  
  301.     /* kickobj should always be set due to conditions of call */
  302.     if(!kickobj || kickobj->otyp == BOULDER
  303.             || kickobj == uball || kickobj == uchain)
  304.         return(0);
  305.  
  306.     if((trap = t_at(x,y)) && trap->tseen) {
  307.         if (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)
  308. #ifdef POLYSELF
  309.             && !passes_walls(uasmon)
  310. #endif
  311.             ) || trap->ttyp == WEB) {
  312.             You("can't kick something that's in a %s!",
  313.                 trap->ttyp == WEB ? "web" : "pit");
  314.             return(1);
  315.         }
  316.     }
  317.  
  318.     if(Fumbling && !rn2(3)) {
  319.         Your("clumsy kick missed.");
  320.         return(1);
  321.     }
  322.  
  323.     /* range < 2 means the object will not move.    */
  324.     /* maybe dexterity should also figure here.     */
  325.     range = (int)((ACURRSTR)/2 - kickobj->owt/40);
  326.  
  327.     if(martial()) range += rnd(3);
  328.  
  329.     /* Mjollnir is magically too heavy to kick */
  330.     if(kickobj->oartifact == ART_MJOLLNIR) range = 1;
  331.  
  332.     /* see if the object has a place to move into */
  333.     if(!ZAP_POS(levl[x+u.dx][y+u.dy].typ) || closed_door(x+u.dx, y+u.dy))
  334.         range = 1;
  335.  
  336.     costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && 
  337.                              costly_spot(x, y));
  338.     insider = (*u.ushops && inside_shop(u.ux, u.uy) &&
  339.                     *in_rooms(x, y, SHOPBASE) == *u.ushops);
  340.  
  341.     /* a box gets a chance of breaking open here */
  342.     if(Is_box(kickobj)) {
  343.         boolean otrp = kickobj->otrapped;
  344.         struct obj *otmp2, *probj = (struct obj *) 0, *temp;
  345.         long loss = 0L;
  346.  
  347.         if(range < 2) pline("THUD!");
  348.  
  349.         for(otmp = kickobj->cobj; otmp; otmp = otmp2) {
  350.             otmp2 = otmp->nobj;
  351.             if (objects[otmp->otyp].oc_material == GLASS
  352.                                 && !rn2(3)) {
  353.                 You("hear a muffled shatter.");
  354.                 if(costly) loss += stolen_value(otmp, x, y, 
  355.                         (boolean)shkp->mpeaceful, TRUE);
  356.                 if (otmp->quan > 1L)
  357.                     useup(otmp);
  358.                 else {
  359.                     temp = otmp;
  360.                     if (otmp == kickobj->cobj) {
  361.                         kickobj->cobj = otmp->nobj;
  362.                         otmp = (struct obj *) 0;
  363.                     } else {
  364.                         probj->nobj = otmp->nobj;
  365.                         otmp = probj;
  366.                     }
  367.                     obfree(temp, (struct obj *) 0);
  368.                 }
  369.             }
  370.             probj = otmp;
  371.         }
  372.         if(costly && loss) {
  373.             if(!insider) {
  374.                   You("caused %ld zorkmids worth of damage!", loss);
  375.             make_angry_shk(shkp, x, y);
  376.             } else
  377.                 You("owe %s %ld zorkmids for objects destroyed.",
  378.                      mon_nam(shkp), loss);
  379.         }
  380.  
  381.         if (kickobj->olocked) {
  382.             if (!rn2(5) || (martial() && !rn2(2))) {
  383.             You("break open the lock!");
  384.             kickobj->olocked = 0;
  385.             kickobj->obroken = 1;
  386.             if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
  387.             return(1);
  388.             }
  389.         } else {
  390.             if (!rn2(3) || (martial() && !rn2(2))) {
  391.             pline("The lid slams open, then falls shut.");
  392.             if (otrp) (void) chest_trap(kickobj, LEG, FALSE);
  393.             return(1);
  394.             }
  395.         }
  396.         if(range < 2) return(1);
  397.         /* else let it fall through to the next cases... */
  398.     }
  399.  
  400.     /* fragile objects should not be kicked */
  401.     if (breaks(kickobj, FALSE)) return(1);
  402.  
  403.     /* potions get a chance of breaking here */
  404.     if(kickobj->oclass == POTION_CLASS) {
  405.         if(rn2(2)) {
  406.             You("smash %s %s!",
  407.               kickobj->quan == 1L ? "the" : "a", xname(kickobj));
  408.             potionbreathe(kickobj);
  409.             if(costly) {
  410.                 long loss = stolen_value(kickobj, kickobj->ox,
  411.                    kickobj->oy, (boolean)shkp->mpeaceful, TRUE);
  412.             if(loss) {
  413.                 if(insider)
  414.                   You("owe %ld zorkmids for objects destroyed.",
  415.                                               loss);
  416.                 else {
  417.                      You("caused %ld zorkmids worth of damage!", loss);
  418.                       make_angry_shk(shkp, kickobj->ox, 
  419.                                         kickobj->oy);
  420.                 }
  421.             }
  422.             }
  423.             useupf(kickobj);
  424.             return(1);
  425.         }
  426.     }
  427.  
  428.     if(IS_ROCK(levl[x][y].typ)) {
  429.         if ((!martial() && rn2(20) > ACURR(A_DEX))
  430. #ifdef POLYSELF
  431.                 || IS_ROCK(levl[u.ux][u.uy].typ)
  432. #endif
  433.                                 ) {
  434.             if (Blind) pline("It doesn't come loose.");
  435.             else pline("%s do%sn't come loose.",
  436.                 The(distant_name(kickobj, xname)),
  437.                 (kickobj->quan == 1L) ? "es" : "");
  438.             return(!rn2(3) || martial());
  439.         }
  440.         if (Blind) pline("It comes loose.");
  441.         else pline("%s come%s loose.",
  442.                The(distant_name(kickobj, xname)),
  443.                (kickobj->quan == 1L) ? "s" : "");
  444.         remove_object(kickobj);
  445.         newsym(x, y);
  446.         if (costly && (!costly_spot(u.ux, u.uy)
  447.                    || !index(u.urooms, *in_rooms(x, y, SHOPBASE))))
  448.             addtobill(kickobj, FALSE, FALSE, FALSE);
  449.         if(!flooreffects(kickobj,u.ux,u.uy,"fall")) {
  450.             place_object(kickobj, u.ux, u.uy);
  451.             stackobj(kickobj);
  452.             newsym(u.ux, u.uy);
  453.         }
  454.         return(1);
  455.     }
  456.  
  457.     isgold = (kickobj->otyp == GOLD_PIECE);
  458.  
  459.     /* too heavy to move.  range is calculated as potential distance from
  460.      * player, so range == 2 means the object may move up to one square
  461.      * from its current position
  462.      */
  463.     if(range < 2 || (isgold && kickobj->quan > 300L)) {
  464.         if(!Is_box(kickobj)) pline("Thump!");
  465.         return(!rn2(3) || martial());
  466.     }
  467.  
  468.     if (kickobj->quan > 1L && !isgold) (void) splitobj(kickobj, 1L);
  469.  
  470.     freeobj(kickobj);
  471.     newsym(x, y);
  472.     mon = bhit(u.dx, u.dy, range, KICKED_WEAPON,
  473.            (int (*)()) 0, (int (*)()) 0, kickobj);
  474.  
  475.     /* a flag to "drop" the object to the next level */
  476.     shipit = (!mon && down_gate(bhitpos.x, bhitpos.y) != -1);
  477.  
  478.     if(mon) {
  479.         notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y);
  480.         /* awake monster if sleeping */
  481.         wakeup(mon);
  482.         if(isgold ? ghitm(mon, kickobj) :    /* caught? */
  483.            thitmonst(mon, kickobj))        /* hit? */
  484.         return(1);
  485.     }
  486.     if(costly &&
  487.        (!costly_spot(bhitpos.x,bhitpos.y) || shipit ||
  488.         *in_rooms(bhitpos.x, bhitpos.y, 0) != *in_rooms(x, y, 0))) {
  489.  
  490.         if(shipit && ship_object(kickobj, bhitpos.x, bhitpos.y, costly))
  491.         return(1);
  492.  
  493.         if(isgold)
  494.         costly_gold(x, y, kickobj->quan);
  495.         else if(costly_spot(u.ux, u.uy) &&
  496.             index(u.urooms, *in_rooms(x, y, 0)))
  497.         addtobill(kickobj, FALSE, FALSE, FALSE);
  498.         else (void)stolen_value(kickobj, x, y, FALSE, FALSE);
  499.     }
  500.  
  501.     if(shipit && ship_object(kickobj, bhitpos.x, bhitpos.y, costly))
  502.         return(1);
  503.     if(flooreffects(kickobj,bhitpos.x,bhitpos.y,"fall")) return(1);
  504.     kickobj->nobj = fobj;
  505.     fobj = kickobj;
  506.     place_object(kickobj, bhitpos.x, bhitpos.y);
  507.     stackobj(kickobj);
  508.     newsym(kickobj->ox, kickobj->oy);
  509.     return(1);
  510. }
  511.  
  512. static char *
  513. kickstr()
  514. {
  515.     static char NEARDATA buf[BUFSZ];
  516.  
  517.     if (kickobj) Sprintf(buf, "kicking %s", doname(kickobj));
  518.     else {
  519.       Strcpy(buf, "kicking ");
  520.       if (IS_STWALL(maploc->typ)) Strcat(buf, "a wall");
  521.       else if (IS_ROCK(maploc->typ)) Strcat(buf, "a rock");
  522.       else if (IS_THRONE(maploc->typ)) Strcat(buf, "a throne");
  523. #ifdef SINKS
  524.       else if (IS_SINK(maploc->typ)) Strcat(buf, "a sink");
  525. #endif
  526.       else if (IS_ALTAR(maploc->typ)) Strcat(buf, "an altar");
  527.       else if (IS_DRAWBRIDGE(maploc->typ)) Strcat(buf, "the drawbridge");
  528.       else {
  529.         switch (maploc->typ) {
  530.         case STAIRS:
  531.             Strcat(buf, "the stairs");
  532.             break;
  533.         case LADDER:
  534.             Strcat(buf, "a ladder");
  535.             break;
  536.         default:
  537.             Strcat(buf, "something wierd");
  538.             break;
  539.         }
  540.       }
  541.     }
  542.     return buf;
  543. }
  544.  
  545. int
  546. dokick()
  547. {
  548.     register int x, y;
  549.     register int avrg_attrib = (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3;
  550.  
  551. #ifdef POLYSELF
  552.     if(nolimbs(uasmon)) {
  553.         You("have no legs to kick with.");
  554.         return(0);
  555.     }
  556.     if(verysmall(uasmon)) {
  557.         You("are too small to do any kicking.");
  558.         return(0);
  559.     }
  560. #endif
  561.     if(Wounded_legs) {
  562.         Your("%s %s in no shape for kicking.",
  563.               ((Wounded_legs & BOTH_SIDES)==BOTH_SIDES)
  564.             ? (const char *)makeplural(body_part(LEG)) : body_part(LEG),
  565.               ((Wounded_legs & BOTH_SIDES)==BOTH_SIDES) ? "are" : "is");
  566.         return(0);
  567.     }
  568.  
  569.     if(near_capacity() > SLT_ENCUMBER) {
  570.         Your("load is too heavy to balance yourself for a kick.");
  571.         return(0);
  572.     }
  573.  
  574.     if(u.uinwater && !rn2(2)) {
  575.         Your("slow motion kick doesn't hit anything.");
  576.         return(0);
  577.     }
  578.  
  579.     if(u.utrap) {
  580.         switch (u.utraptype) {
  581.             case TT_PIT:
  582.             pline("There's nothing to kick down here.");
  583.             case TT_WEB:
  584.             case TT_BEARTRAP:
  585.             You("can't move your %s!", body_part(LEG));
  586.         }
  587.         return(0);
  588.     }
  589.  
  590.     if(!getdir(NULL)) return(0);
  591.     if(!u.dx && !u.dy) return(0);
  592.  
  593.     x = u.ux + u.dx;
  594.     y = u.uy + u.dy;
  595.  
  596.     if(u.uswallow) {
  597.         switch(rn2(3)) {
  598.         case 0:  You("can't move your %s!", body_part(LEG));
  599.              break;
  600.         case 1:  if (is_animal(u.ustuck->data)) {
  601.                 pline("%s burps loudly.", Monnam(u.ustuck));
  602.                 break;
  603.              }
  604.         default: Your("feeble kick has no effect."); break;
  605.         }
  606.         return(1);
  607.     }
  608.  
  609.     wake_nearby();
  610.     u_wipe_engr(2);
  611.  
  612.     maploc = &levl[x][y];
  613.  
  614.     /* The next four tests should stay in      */
  615.     /* their present order: monsters, objects, */
  616.     /* non-doors, doors.               */
  617.  
  618.     if(MON_AT(x, y)) {
  619.         kick_monster(x, y);
  620.         if((Is_airlevel(&u.uz) || Levitation) && flags.move) {
  621.             int range;
  622.             struct monst *mon;
  623.  
  624.             mon = m_at(x,y);
  625.             range = (3*(int)mon->data->cwt) /
  626.             ((int)uasmon->cwt + (weight_cap() + inv_weight()));
  627.             if(range < 1) range = 1;
  628.             hurtle(-u.dx, -u.dy, range);
  629.         }
  630.         return(1);
  631.     }
  632.  
  633.     kickobj = (struct obj *)0;
  634.     if (OBJ_AT(x, y) &&
  635.         (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)
  636.          || sobj_at(BOULDER,x,y))) {
  637.         if(kick_object(x, y)) {
  638.             if(Is_airlevel(&u.uz))
  639.             hurtle(-u.dx, -u.dy, 1); /* assume it's light */
  640.             return(1);
  641.         }
  642.         goto ouch;
  643.     }
  644.  
  645.     if(!IS_DOOR(maploc->typ)) {
  646.         if(maploc->typ == SDOOR) {
  647.             if(!Levitation && rn2(30) < avrg_attrib) {
  648.             pline("Crash!  You kick open a secret door!");
  649.             exercise(A_DEX, TRUE);
  650.             maploc->typ = DOOR;
  651.             if(maploc->doormask & D_TRAPPED) {
  652.                 b_trapped("door");
  653.                 maploc->doormask = D_NODOOR;
  654.             } else
  655.                 maploc->doormask = D_ISOPEN;
  656.             if (Blind)
  657.                 feel_location(x,y);    /* we know its gone */
  658.             else
  659.                 newsym(x,y);
  660.             unblock_point(x,y);    /* vision */
  661.             return(1);
  662.             } else goto ouch;
  663.         }
  664.         if(maploc->typ == SCORR) {
  665.             if(!Levitation && rn2(30) < avrg_attrib) {
  666.             pline("Crash!  You kick open a secret passage!");
  667.             exercise(A_DEX, TRUE);
  668.             maploc->typ = CORR;
  669.             if (Blind)
  670.                 feel_location(x,y);    /* we known its gone */
  671.             else
  672.                 newsym(x,y);
  673.             unblock_point(x,y);    /* vision */
  674.             return(1);
  675.             } else goto ouch;
  676.         }
  677.         if(IS_THRONE(maploc->typ)) {
  678.             register int i;
  679.             if(Levitation) goto dumb;
  680.             if((Luck < 0 || maploc->doormask) && !rn2(3)) {
  681.             maploc->typ = ROOM;
  682.             maploc->doormask = 0; /* don't leave loose ends.. */
  683.             mkgold((long)rnd(200), x, y);
  684.             if (Blind)
  685.                 pline("CRASH!  You destroy it.");
  686.             else {
  687.                 pline("CRASH!  You destroy the throne.");
  688.                 newsym(x, y);
  689.             }
  690.             exercise(A_DEX, TRUE);
  691.             return(1);
  692.             } else if(Luck > 0 && !rn2(3) && !maploc->looted) {
  693.             mkgold((long) rn1(201, 300), x, y);
  694.             i = Luck + 1;
  695.             if(i > 6) i = 6;
  696.             while(i--) (void) mkobj_at(GEM_CLASS, x, y, TRUE);
  697.             if (Blind)
  698.                 You("kick something loose!");
  699.             else {
  700.                 You("kick loose some ornamental coins and gems!");
  701.                 newsym(x, y);
  702.             }
  703.             /* prevent endless milking */
  704.             maploc->looted = T_LOOTED;
  705.             return(1);
  706.             } else if (!rn2(4)) {
  707.             if(dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) {
  708.                 fall_through(FALSE);
  709.                 return(1);
  710.             } else goto ouch;
  711.             }
  712.             goto ouch;
  713.         }
  714.         if(IS_ALTAR(maploc->typ)) {
  715.             if(Levitation) goto dumb;
  716.             You("kick %s.",(Blind ? "something" : "the altar"));
  717.             if(!rn2(3)) goto ouch;
  718.             altar_wrath(x, y);
  719.             exercise(A_DEX, TRUE);
  720.             return(1);
  721.         }
  722. #ifdef SINKS
  723.         if(IS_SINK(maploc->typ)) {
  724.             if(Levitation) goto dumb;
  725.             if(rn2(5)) {
  726.             if(flags.soundok)
  727.                 pline("Klunk!  The pipes vibrate noisily.");
  728.             else pline("Klunk!");
  729.             exercise(A_DEX, TRUE);
  730.             return(1);
  731.             } else if(!(maploc->looted & S_LPUDDING) && !rn2(3) &&
  732.               !(mons[PM_BLACK_PUDDING].geno &
  733.                 (G_GENOD | G_EXTINCT))) {
  734.             if (Blind)
  735.                 You("hear a gushing sound.");
  736.             else
  737.                 pline("A %s ooze gushes up from the drain!",
  738.                       Hallucination ? hcolor() : Black);
  739.             (void) makemon(&mons[PM_BLACK_PUDDING], x, y);
  740.             exercise(A_DEX, TRUE);
  741.             newsym(x,y);
  742.             maploc->looted |= S_LPUDDING;
  743.             return(1);
  744.             } else if(!(maploc->looted & S_LDWASHER) && !rn2(3) &&
  745. # ifndef POLYSELF
  746.                   poly_gender() != 2 &&
  747. # endif
  748.                   !(mons[poly_gender() == 1 ?
  749.                       PM_INCUBUS : PM_SUCCUBUS].geno &
  750.                   (G_GENOD | G_EXTINCT))) {
  751.             /* can't resist... */
  752.             pline("%s returns!", (Blind ? "Something" :
  753.                             "The dish washer"));
  754.             if (makemon(&mons[poly_gender() == 1 ?
  755.                 PM_INCUBUS : PM_SUCCUBUS], x, y)) newsym(x,y);
  756.             maploc->looted |= S_LDWASHER;
  757.             exercise(A_DEX, TRUE);
  758.             return(1);
  759.             } else if(!rn2(3)) {
  760.             pline("Flupp!  %s.", (Blind ?
  761.                       "You hear a sloshing sound" :
  762.                       "Muddy waste pops up from the drain"));
  763.             if(!(maploc->looted & S_LRING)) { /* once per sink */
  764.                 if (!Blind)
  765.                 You("see a ring shining in its midst.");
  766.                 (void) mkobj_at(RING_CLASS, x, y, TRUE);
  767.                 newsym(x, y);
  768.                 exercise(A_DEX, TRUE);
  769.                 exercise(A_WIS, TRUE);    /* a discovery! */
  770.                 maploc->looted |= S_LRING;
  771.             }
  772.             return(1);
  773.             }
  774.             goto ouch;
  775.         }
  776. #endif
  777.         if (maploc->typ == STAIRS || maploc->typ == LADDER ||
  778.                             IS_STWALL(maploc->typ)) {
  779.             if(!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN)
  780.             goto dumb;
  781. ouch:
  782.             pline("Ouch!  That hurts!");
  783.             exercise(A_DEX, FALSE);
  784.             exercise(A_STR, FALSE);
  785.             if (Blind) feel_location(x,y); /* we know we hit it */
  786.             if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
  787.             losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), kickstr(),
  788.             KILLED_BY);
  789.             if(Is_airlevel(&u.uz) || Levitation)
  790.             hurtle(-u.dx, -u.dy, rn1(2,4)); /* assume it's heavy */
  791.             return(1);
  792.         }
  793.         if (is_drawbridge_wall(x,y) >= 0) {
  794.             pline("The drawbridge is unaffected.");
  795.             if(Levitation)
  796.             hurtle(-u.dx, -u.dy, rn1(2,4)); /* it's heavy */
  797.             return(1);
  798.         }
  799.         goto dumb;
  800.     }
  801.  
  802.     if(maploc->doormask == D_ISOPEN ||
  803.        maploc->doormask == D_BROKEN ||
  804.        maploc->doormask == D_NODOOR) {
  805. dumb:
  806.         exercise(A_DEX, FALSE);
  807.         if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) {
  808.             You("kick at empty space.");
  809.         } else {
  810.             pline("Dumb move!  You strain a muscle.");
  811.             exercise(A_STR, FALSE);
  812.             set_wounded_legs(RIGHT_SIDE, 5 + rnd(5));
  813.         }
  814.         if(Is_airlevel(&u.uz) || Levitation)
  815.             hurtle(-u.dx, -u.dy, rn2(2));
  816.         return(0);
  817.     }
  818.  
  819.     /* not enough leverage to kick open doors while levitating */
  820.     if(Levitation) goto ouch;
  821.  
  822.     exercise(A_DEX, TRUE);
  823.     /* door is known to be CLOSED or LOCKED */
  824.     if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) {
  825.         /* break the door */
  826.         if(maploc->doormask & D_TRAPPED) {
  827.             pline("As you kick the door, it explodes!");
  828.             exercise(A_STR, FALSE);
  829.             b_trapped("door");
  830.             maploc->doormask = D_NODOOR;
  831.         } else if(ACURR(A_STR) > 18 && !rn2(5) &&
  832.               !*in_rooms(x, y, SHOPBASE)) {
  833.             pline("As you kick the door, it shatters to pieces!");
  834.             exercise(A_STR, TRUE);
  835.             maploc->doormask = D_NODOOR;
  836.         } else {
  837.             pline("As you kick the door, it crashes open!");
  838.             exercise(A_STR, TRUE);
  839.             if(*in_rooms(x, y, SHOPBASE)) {
  840.             add_damage(x, y, 400L);
  841.             pay_for_damage("break");
  842.             }
  843.             maploc->doormask = D_BROKEN;
  844.         }
  845.         if (Blind)
  846.             feel_location(x,y);        /* we know we broke it */
  847.         else
  848.             newsym(x,y);
  849.         unblock_point(x,y);        /* vision */
  850.     } else {
  851.         if (Blind) feel_location(x,y);    /* we know we hit it */
  852.         exercise(A_STR, TRUE);
  853.         pline("WHAMMM!!!");
  854.     }
  855.     return(1);
  856. }
  857.  
  858. static const char *
  859. gate_str(gate)
  860. register xchar gate;
  861. {
  862.     const char *optr;
  863.  
  864.     switch(gate) {
  865.         case 0:
  866.         case 4:  optr = "through the trap door."; break;
  867.         case 1:
  868.         case 3:  optr = "down the stairs."; break;
  869.         case 2:  optr = "down the ladder."; break;
  870.         default: optr = "down out of sight."; break;
  871.     }
  872.     return(optr);
  873. }
  874.  
  875. static
  876. void
  877. drop_to(cc, loc)
  878. coord *cc;
  879. register xchar loc;
  880. {
  881.     switch(loc) {
  882.         case 0: if(In_endgame(&u.uz) || (Is_botlevel(&u.uz) &&
  883.                   !Is_stronghold(&u.uz))) {
  884.             cc->y = 0;
  885.             return;
  886.             }
  887.             if(Is_stronghold(&u.uz)) {
  888.             cc->x = valley_level.dnum;
  889.             cc->y = valley_level.dlevel;
  890.             break;
  891.             } /* else fall to the next cases */
  892.         case 1:
  893.         case 2:
  894.             cc->x = u.uz.dnum;
  895.             cc->y = u.uz.dlevel + 1;
  896.             break;
  897.         case 3:
  898.             cc->x = sstairs.tolev.dnum;
  899.             cc->y = sstairs.tolev.dlevel;
  900.             break;
  901.         default:
  902.             cc->y = 0;
  903.     }
  904. }
  905.  
  906. void
  907. impact_drop(missile, x, y, dlev)
  908. register struct obj *missile;
  909. register xchar x, y, dlev;
  910. {
  911.     xchar toloc;
  912.     register struct obj *obj, *obj2;
  913.     register struct monst *shkp;
  914.     long oct, dct, price, debit, robbed;
  915.     boolean angry, costly, isrock;
  916.     coord cc;
  917.  
  918.     if(!OBJ_AT(x, y)) return;
  919.  
  920.     toloc = down_gate(x, y);
  921.     drop_to(&cc, toloc);
  922.     if (!cc.y) return;
  923.  
  924.     if (dlev) {
  925.         /* send objects next to player falling through trap door.
  926.          * checked in obj_delivery().
  927.          */
  928.         toloc = 4;
  929.         cc.y = dlev;
  930.     }
  931.  
  932.     costly = costly_spot(x, y);
  933.     price = debit = robbed = 0L;
  934.     angry = FALSE;
  935.     shkp = (struct monst *) 0;
  936.     /* if 'costly', we must keep a record of ESHK(shkp) before
  937.      * it undergoes changes through the calls to stolen_value.
  938.      * the angry bit must be reset, if needed, in this fn, since
  939.      * stolen_value is called under the 'silent' flag to avoid
  940.      * unsavory pline repetitions.
  941.      */
  942.     if(costly) {
  943.         if((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 
  944.                                                (struct monst *)0) {
  945.         debit    = ESHK(shkp)->debit;
  946.         robbed    = ESHK(shkp)->robbed;
  947.         angry    = !shkp->mpeaceful;
  948.         }
  949.     }
  950.  
  951.     isrock = (missile && missile->otyp == ROCK);
  952.     oct = dct = 0L;
  953.     for(obj = level.objects[x][y]; obj; obj = obj2) {
  954.         obj2 = obj->nexthere;
  955.         if(obj == missile) continue;
  956.         /* number of objects in the pile */
  957.         oct += obj->quan;
  958.         /* boulders can fall too, but rarely & never due to rocks */
  959.         if((isrock && obj->otyp == BOULDER) ||
  960.            rn2(obj->otyp == BOULDER ? 30 : 3)) continue;
  961.         freeobj(obj);
  962.  
  963.         if(costly) {
  964.             price += stolen_value(obj, x, y,
  965.                 (costly_spot(u.ux, u.uy) &&
  966.                  index(u.urooms, *in_rooms(x, y, SHOPBASE))),
  967.                 TRUE);
  968.             /* set obj->no_charge to 0 */
  969.             if(Is_container(obj))
  970.                 picked_container(obj); /* does the right thing */
  971.             if(obj->otyp != GOLD_PIECE)
  972.                 obj->no_charge = 0;
  973.         }
  974.         obj->nobj = migrating_objs;
  975.         migrating_objs = obj;
  976.  
  977.         obj->ox = cc.x;
  978.         obj->oy = cc.y;
  979.         obj->owornmask = (long)toloc;
  980.  
  981.         /* number of fallen objects */
  982.         dct += obj->quan;
  983.     }
  984.  
  985.     if (dct) {    /* at least one object fell */
  986.         const char *what = (dct == 1L ? "object falls" : "objects fall");
  987.         if (missile)
  988.         pline("From the impact, %sother %s.",
  989.             dct == oct ? "the " : dct == 1L ? "an" : "", what);
  990.         else
  991.         pline("%s adjacent %s %s",
  992.             oct == dct ? (dct > 1L ? "All the" : "The") :
  993.                 (dct == 1L ? "One of the" : "Some of the"),
  994.             what, gate_str(toloc));
  995.     }
  996.  
  997.     if(costly && shkp && price) {
  998.         if(ESHK(shkp)->robbed > robbed) {
  999.             You("removed %ld zorkmids worth of goods!", price);
  1000.             if(cansee(shkp->mx, shkp->my)) {
  1001.             if(ESHK(shkp)->customer[0] == 0)
  1002.                 (void) strncpy(ESHK(shkp)->customer,
  1003.                        plname, PL_NSIZ);
  1004.             if(angry)
  1005.                 pline("%s is infuriated!", Monnam(shkp));
  1006.             else pline("\"%s, you are a thief!\"", plname);
  1007.             } else  You("hear a scream, \"Thief!\"");
  1008.             hot_pursuit(shkp);
  1009.             (void) angry_guards(FALSE);
  1010.             return;
  1011.         }
  1012.         if(ESHK(shkp)->debit > debit)
  1013.             You("owe %s %ld zorkmids for goods lost.",
  1014.             Monnam(shkp),
  1015.             (ESHK(shkp)->debit - debit));
  1016.     }
  1017.  
  1018. }
  1019.  
  1020. /* NOTE: ship_object assumes otmp was FREED from fobj or invent.
  1021.  * <x,y> is the point of drop.  otmp is _not_ an <x,y> resident:
  1022.  * otmp is either a kicked, dropped, or thrown object.
  1023.  */
  1024. boolean
  1025. ship_object(otmp, x, y, shop_floor_obj)
  1026. register xchar  x, y;
  1027. register struct obj *otmp;
  1028. register boolean shop_floor_obj;
  1029. {
  1030.     register xchar ox, oy;
  1031.     register xchar toloc = down_gate(x, y);
  1032.     /* toloc -- destination location: */
  1033.         /*    0: rnd loc,
  1034.          *    1: <,
  1035.          *    2: < ladder,
  1036.          *    3: sstairs up
  1037.          *    4: near player (trapdoor)
  1038.          */
  1039.     coord cc;
  1040.     /* objects always fall down ladder, a chance of stay otherwise */
  1041.     register boolean nodrop = (toloc != 2 && rn2(3));
  1042.     register boolean unpaid, container, impact = FALSE;
  1043.     int n = 0;
  1044.  
  1045.     if(!otmp) return(FALSE);
  1046.     if(toloc == -1) return(FALSE);
  1047.  
  1048.     drop_to(&cc, toloc);
  1049.     if(!cc.y) return(FALSE);
  1050.  
  1051.     container = Is_container(otmp);
  1052.  
  1053.     unpaid = (otmp->unpaid || (container && count_unpaid(otmp->cobj)));
  1054.  
  1055.     if(OBJ_AT(x, y)) {
  1056.         register struct obj *obj;
  1057.  
  1058.         for(obj = level.objects[x][y]; obj; obj = obj->nexthere)
  1059.         if(obj != otmp) n++;
  1060.         if(n) impact = TRUE;
  1061.     }
  1062.  
  1063.     otransit_msg(otmp, toloc, nodrop, n);
  1064.  
  1065.     if(nodrop) {
  1066.         otmp->nobj = fobj;
  1067.         fobj = otmp;
  1068.         place_object(otmp, x, y);
  1069.         stackobj(otmp);
  1070.         newsym(otmp->ox, otmp->oy);
  1071.         if(impact) goto chain_reaction;
  1072.         else return(TRUE);
  1073.     }
  1074.  
  1075.     if(unpaid || shop_floor_obj) {
  1076.         if(unpaid) {
  1077.         subfrombill(otmp, shop_keeper(*u.ushops));
  1078.         (void)stolen_value(otmp, u.ux, u.uy, TRUE, FALSE);
  1079.         } else {
  1080.             ox = otmp->ox;
  1081.         oy = otmp->oy;
  1082.         (void)stolen_value(otmp, ox, oy,
  1083.               (costly_spot(u.ux, u.uy) &&
  1084.                   index(u.urooms, *in_rooms(ox, oy, SHOPBASE))),
  1085.               FALSE);
  1086.         }
  1087.         /* set otmp->no_charge to 0 */
  1088.         if(container)
  1089.             picked_container(otmp); /* happens to do the right thing */
  1090.         if(otmp->otyp != GOLD_PIECE)
  1091.             otmp->no_charge = 0;
  1092.     }
  1093.  
  1094.     otmp->nobj = migrating_objs;
  1095.     migrating_objs = otmp;
  1096.  
  1097.     otmp->ox = cc.x;
  1098.     otmp->oy = cc.y;
  1099.     otmp->owornmask = (long)toloc;
  1100. chain_reaction:
  1101.     if(impact) {
  1102.         /* the objs impacted may be in a shop other than
  1103.          * the one in which the hero is located.  another
  1104.          * check for a shk is made in impact_drop.  it is, e.g.,
  1105.          * possible to kick/throw an object belonging to one
  1106.          * shop into another shop through a gap in the wall,
  1107.          * and cause objects belonging to the other shop to
  1108.          * fall down a trapdoor--thereby getting two shopkeepers
  1109.          * angry at the hero in one shot.
  1110.          */
  1111.         impact_drop(otmp, x, y, 0);
  1112.         newsym(x,y);
  1113.     }
  1114.     return(TRUE);
  1115. }
  1116.  
  1117. void
  1118. obj_delivery()
  1119. {
  1120.     register struct obj *otmp, *otmp0 = (struct obj *)0, *otmp2;
  1121.  
  1122.     for(otmp = migrating_objs; otmp; otmp = otmp2) {
  1123.  
  1124.         otmp2 = otmp->nobj;
  1125.  
  1126.         if(otmp->ox == u.uz.dnum && otmp->oy == u.uz.dlevel) {
  1127.         if(otmp == migrating_objs)
  1128.             migrating_objs = otmp->nobj;
  1129.         else
  1130.             otmp0->nobj = otmp->nobj;
  1131.         otmp->nobj = fobj;
  1132.         fobj = otmp;
  1133.  
  1134.         switch((xchar)otmp->owornmask) {
  1135.             xchar *xlocale, *ylocale;
  1136.  
  1137.             case 1: xlocale = &xupstair; ylocale = &yupstair;
  1138.                 goto common;
  1139.             case 2: xlocale = &xupladder; ylocale = &yupladder;
  1140.                 goto common;
  1141.             case 3: xlocale = &sstairs.sx; ylocale = &sstairs.sy;
  1142.                 goto common;
  1143.             case 4: { /* hero falls down trapdoor with objects */
  1144.                   xchar nx, ny;
  1145.                   int cnt = 0;
  1146.  
  1147.                   do {
  1148.                   nx = u.ux - 1 + rn2(3);
  1149.                   ny = u.uy - 1 + rn2(3);
  1150.                   } while((nx < 1 || nx > COLNO-2 ||
  1151.                        ny < 1 || ny > ROWNO-2 ||
  1152.                        is_pool(nx,ny) || is_lava(nx,ny) ||
  1153.                        !ACCESSIBLE(levl[nx][ny].typ) ||
  1154.                        closed_door(nx, ny)
  1155.                       ) && cnt++ <= 50);
  1156.  
  1157.                   if(cnt >= 50) goto scatter; /* safety */
  1158.                   xlocale = &nx;
  1159.                   ylocale = &ny;
  1160.                 }
  1161. common:
  1162.                 if (*xlocale && *ylocale) {
  1163.                 place_object(otmp, *xlocale, *ylocale);
  1164.                 stackobj(otmp);
  1165.                 break;
  1166.                 } /* else fall through */
  1167.             default:
  1168. scatter:
  1169.                 rloco(otmp);
  1170.                 break;
  1171.         }
  1172.         otmp->owornmask = 0L;
  1173.         } else
  1174.         otmp0 = otmp;
  1175.     }
  1176. }
  1177.  
  1178. static void
  1179. otransit_msg(otmp, loc, nodrop, num)
  1180. register struct obj *otmp;
  1181. register xchar loc;
  1182. register boolean nodrop;
  1183. int num;
  1184. {
  1185.     char obuf[BUFSZ];
  1186.  
  1187.     Sprintf(obuf, "%s%s",
  1188.          (otmp->otyp == CORPSE &&
  1189.             type_is_pname(&mons[otmp->corpsenm])) ? "" : "The ",
  1190.          xname(otmp));
  1191.  
  1192.     if(num) { /* means: other objects are impacted */
  1193.         Sprintf(eos(obuf), " hit%s %s object%s",
  1194.               otmp->quan == 1L ? "s" : "",
  1195.               num == 1 ? "another" : "other",
  1196.               num > 1 ? "s" : "");
  1197.         if(nodrop)
  1198.         Sprintf(eos(obuf), " and stop%s.",
  1199.                  otmp->quan == 1L ? "s" : "");
  1200.         else
  1201.         Sprintf(eos(obuf), " and fall%s %s",
  1202.                 otmp->quan == 1L ? "s" : "", gate_str(loc));
  1203.         pline(obuf);
  1204.     } else if(!nodrop)
  1205.         pline("%s fall%s %s", obuf,
  1206.           otmp->quan == 1L ? "s" : "",
  1207.           gate_str(loc));
  1208. }
  1209.  
  1210. xchar
  1211. down_gate(x, y)
  1212. xchar x, y;
  1213. {
  1214.     register struct trap *ttmp = t_at(x, y);
  1215.  
  1216.     if(ttmp && ttmp->ttyp == TRAPDOOR && ttmp->tseen) return 0;
  1217.     if(xdnstair == x && ydnstair == y) return 1;
  1218.     if(xdnladder == x && ydnladder == y) return 2;
  1219.     if(sstairs.sx == x && sstairs.sy == y && !sstairs.up) return 3;
  1220.     return -1;
  1221. }
  1222.  
  1223. /*dokick.c*/
  1224.